<?php
/**
 * Created by PhpStorm.
 * User: BlueIdeaLirui
 * Date: 2019/09/04
 * Time: 14:58
 */

namespace business\elasticsearch\services;

use business\base\models\AreaModel;
use business\base\services\BasicCategoryService;
use business\elasticsearch\repositories\SupplierBasicRepository;
use common\utils\DateTimeUtils;

class SupplierBasicService
{
    /**
     * 返回区域TOP30供应商行业列表数据
     * @param string $region
     */
    public function getSupplierRankingByAreaList
    (
        $region = '',
        $isTotalQuantity = true
    ) {
        $query = [];

        // 构建查询条件
        static::constructingSupplierRankingByAreaQueryCond($query, $region);

        $include = [];

        list(, $data) = (new SupplierBasicRepository())->querySupplierBasicList(
            $query, $include, static::constructingSupplierRankingByAreaAggs($isTotalQuantity));

        $bucketsList = static::filterSupplierRankingByArea(
            array_slice($data['service_category_aggs']['service_category_term']['buckets'],
                0, 30));

        $result['list'] = !empty($bucketsList) ? $bucketsList : null;

        !empty($result['list']) && static::saveCacheRecord(
            md5(serialize(['name' => 'supplier_ranking', 'region' => $region])), $result);

        return $result;
    }

    /**
     * 存储到缓存
     * @param string $key
     * @param array $data
     * @param int $expire
     */
    protected static function saveCacheRecord
    (
        $key = '',
        $data = [],
        $expire = 600
    ) {
        $redis = \Yii::$app->redis;

        $value = '';

        if (is_array($data)) {
            $tempStr = serialize($data);
            $value = base64_encode(gzcompress($tempStr));
        } else {
            $value = $data;
        }

        $redis->set($key, $value);
        $redis->expire($key, $expire);
    }

    /**
     * 过滤数据
     * @param array $buckets
     * @return array
     */
    protected static function filterSupplierRankingByArea($buckets = [])
    {
        if (!empty($buckets)) {
            $data = [];
            $basicCategoryService = new BasicCategoryService();
            foreach ($buckets as $value) {
                $tmp['category_code'] = $value['key'];
                $tmp['category_name'] = $basicCategoryService->getCategoryNameByCode($value['key']);
                $tmp['count']         = $value['doc_count'];
                $data[]               = $tmp;
            }

            return $data;
        }

        return [];
    }

    /**
     * 构建区域TOP30供应商行业查询条件
     * @param array $query
     * @param string $region
     */
    protected static function constructingSupplierRankingByAreaQueryCond
    (
        & $query = [],
        $region = ''
    ) {
        $bool = [];

        foreach (['status' => 2, 'state' => 2] as $key => $item) {
            $query['bool']['must'][] = [
                'match_phrase' => [
                    $key => $item
                ]
            ];
        }

        // 构建项目地区查询
        if (!empty($region)) {
            $region = json_decode($region, true);
            foreach ($region as $item) {
                $bool[0]['bool']['should'][] = [
                    'match_phrase' => [
                        'city_code.keyword' => $item
                    ]
                ];
                $bool[0]['bool']['should'][] = [
                    'match_phrase' => [
                        'province_code.keyword' => $item
                    ]
                ];
            }
        }

        $query['bool']['must'][] = $bool;
    }

    /**
     * 构建区域TOP30供应商行业聚合
     * @param bool $isTotalQuantity
     * @return array
     */
    protected static function constructingSupplierRankingByAreaAggs($isTotalQuantity = true)
    {
        return [
            [
                'name' => 'service_category_aggs',
                'options' => [
                    'nested' => [
                        'path' => 'service_category'
                    ],
                    'aggs' => [
                        'service_category_term' => [
                            'terms' => [
                                'field' => 'service_category.category_code',
                                'order' => [
                                    '_count' => 'desc'
                                ],
                                'size' => $isTotalQuantity ? pow(2,31) - 1 : 0
                            ],
                        ]
                    ]
                ]
            ],
        ];
    }

    /**
     * 返回报名招标\招募行业TOP30数据列表
     * @param string $region
     * @param bool $isTotalQuantity
     * @return mixed
     */
    public function getApplyRecruitmentBiddingByAreaList
    (
        $region = '',
        $monthlyNumber = 0,
        $isTotalQuantity = true
    ) {
        $query = [];

        // 构建查询条件
        static::constructingApplyRecruitmentBiddingByAreaQueryCond($query, $region);

        $include = [];

        list(, $data) = (new SupplierBasicRepository())->querySupplierBasicList(
            $query
            , $include
            , static::constructingApplyRecruitmentBiddingByAreaAggs($isTotalQuantity, $monthlyNumber));

        if (!empty($data)) {
            $temp = [];

            foreach (['recruit_item', 'tendering_item'] as $value) {
                array_push($temp,
                    static::filterApplyRecruitmentBiddingByArea(
                        $data[$value . '_aggs']['filter_date'][$value . '_term']['buckets']));
            }

            list($recruitItemTerm, $tenderingItemTerm) = $temp;

            $list = array_slice(
                static::getSortRecord(static::mergeRecruitmentBiddingCount(
                    $recruitItemTerm, $tenderingItemTerm), 'count', SORT_DESC), 0, 30);
        }

        $result['list'] = !empty($list) ? $list : null;
        $result['total'] = 0;

        if (!empty($list)) {
            foreach ($list as $item) {
                $result['total'] += $item['count'];
            }
        }

        !empty($result['list']) && static::saveCacheRecord(
            md5(serialize(['name' => 'recruitment_bidding', 'region' => $region, 'monthly_number' => $monthlyNumber])),
            $result);

        return $result;
    }

    /**
     * 合并报名招标\招募行业分类数量
     * @return array|mixed
     */
    protected static function mergeRecruitmentBiddingCount()
    {
        $args = func_get_args();

        if (empty($args)) {
            return [];
        }

        $recruitArr   = array_shift($args);
        $tenderingArr = end($args);

        array_walk($recruitArr,
            function (&$value, $key)
            use (
                &$temp,
                $tenderingArr
            ) {
            foreach ($tenderingArr as $item) {
                if ($value['category_name'] == $item['category_name']) {
                    $value['count'] += $item['count'];
                    break;
                }
            }
        });

        return !empty($recruitArr) ? array_merge(
            $recruitArr, static::getDiffArrayByCategoryName($tenderingArr, $recruitArr)) : [];
    }

    /**
     * 返回数据的差集
     * @param $arr1
     * @param $arr2
     * @param string $name
     * @return array
     */
    protected static function getDiffArrayByCategoryName
    (
        $arr1,
        $arr2,
        $name = 'category_name'
    ) {
        try{
            $res = [];
            foreach($arr2 as $item) $tmpArr[$item[$name]] = $item;
            foreach($arr1 as $v) if(! isset($tmpArr[$v[$name]])) $res[] = $v;
            return $res;
        }catch (\Exception $exception){
            return $arr1;
        }
    }

    /**
     * 数组内部排序
     * @return mixed|null
     * @throws \Exception
     */
    protected static function getSortRecord()
    {
        $args = func_get_args();
        if (empty($args)) {
            return null;
        }
        $arr = array_shift($args);
        if (!is_array($arr)) {
            throw new \Exception('第一个参数不为数组');
        }
        foreach($args as $key => $field){
            if(is_string($field)){
                $temp = array();
                foreach($arr as $index => $val){
                    $temp[$index] = $val[$field];
                }
                $args[$key] = $temp;
            }
        }
        $args[] = &$arr; //引用值
        call_user_func_array('array_multisort', $args);
        return array_pop($args);
    }

    /**
     * 过滤数据
     * @param array $buckets
     * @return array
     */
    protected static function filterApplyRecruitmentBiddingByArea($buckets = [])
    {
        if (!empty($buckets)) {
            $data = [];
            foreach ($buckets as $value) {
                $tmp['category_name'] = $value['key'];
                $tmp['count']         = $value['doc_count'];
                $data[]               = $tmp;
            }

            return $data;
        }

        return [];
    }

    /**
     * 构建报名招标\招募行业TOP30数据查询条件
     * @param array $query
     * @param string $region
     */
    protected static function constructingApplyRecruitmentBiddingByAreaQueryCond
    (
        & $query = [],
        $region = ''
    ) {
        $bool = [];

        foreach (['status' => 2, 'state' => 2] as $key => $item) {
            $query['bool']['must'][] = [
                'match_phrase' => [
                    $key => $item
                ]
            ];
        }

        // 构建项目地区查询
        if (!empty($region)) {
            $region = json_decode($region, true);
            foreach ($region as $item) {
                $bool[0]['bool']['should'][] = [
                    'match_phrase' => [
                        'city_code.keyword' => $item
                    ]
                ];
                $bool[0]['bool']['should'][] = [
                    'match_phrase' => [
                        'province_code.keyword' => $item
                    ]
                ];
            }
        }

        $query['bool']['must'][] = $bool;
    }

    /**
     * 构建报名招标\招募行业TOP30数据聚合
     * @param bool $isTotalQuantity
     * @return array
     */
    protected static function constructingApplyRecruitmentBiddingByAreaAggs
    (
        $isTotalQuantity = true,
        $monthlyNumber = 0
    ) {
        if (!empty($monthlyNumber)) {
            $beginDate = DateTimeUtils::convertDate(
                strtotime('-' . $monthlyNumber . 'month'));
            $endDate   = DateTimeUtils::convertDate(DateTimeUtils::time());
        }

        $aggsArr = [
            'tendering_item' => ['date' => 'register_date', 'field' => 'category_name'],
            'recruit_item'   => ['date' => 'register_time', 'field' => 'name']
        ];

        $rtn = [];

        array_walk($aggsArr,
            function ($value, $key)
            use (
                &$rtn,
                $beginDate,
                $endDate,
                $isTotalQuantity
            ) {
            array_push($rtn, [
                'name' => $key . '_aggs',
                'options' => [
                    'nested' => [
                        'path' => $key
                    ],
                    'aggs' => [
                        'filter_date' => [
                            'filter' => [
                                'range' => [
                                    $key . '.' . $value['date'] => [
                                        'gte' => $beginDate,
                                        'lte' => $endDate
                                    ]
                                ]
                            ],
                            'aggs' => [
                                $key . '_term' => [
                                    'terms' => [
                                        'field' => $key . '.' . $value['field'] . '.keyword',
                                        'order' => [
                                            '_count' => 'desc'
                                        ],
                                        'size' => $isTotalQuantity ? pow(2,31) - 1 : 0
                                    ],
                                ]
                            ]
                        ]
                    ]
                ]
            ]);
        });

        return $rtn;
    }
}
